home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / lpdfilt.c < prev    next >
C/C++ Source or Header  |  1993-07-30  |  14KB  |  613 lines

  1. /* Internet LPD Server filters
  2.  *   written by David Johnson (dave@cs.olemiss.edu)
  3.  *
  4.  * This code is in the public domain.
  5.  *
  6.  * Revision History:
  7.  *
  8.  * Revision 1.4  91/09/25  dave
  9.  * Changed subtraction of integer 1 to character '1' in wait_for_printer()
  10.  *
  11.  * Revision 1.3  91/09/19  dave
  12.  * Handle output processing for expanding tabs
  13.  *
  14.  * Revision 1.2  91/09/17  dave
  15.  * Handle output processing for each device, not just internal
  16.  *
  17.  * Revision 1.1  91/09/14  dave (from marko winblad)
  18.  * Correction to definition of variable 'c' in input_char() to int.
  19.  *
  20.  * Revision 1.0  91/09/04  dave
  21.  * Initial Release
  22.  *
  23.  */
  24. #include <stdio.h>
  25. #include <fcntl.h>
  26. #include <ctype.h>
  27. #include <string.h>
  28. #include <time.h>
  29. #include <sys/stat.h>
  30. #include <dos.h>
  31. #ifdef    __TURBOC__
  32. #include <io.h>
  33. #include <dir.h>
  34. #endif
  35. #include "global.h"
  36. #include "mbuf.h"
  37. #include "proc.h"
  38. #include "iface.h"
  39. #include "asy.h"
  40. #include "socket.h"
  41. #include "dirutil.h"
  42. #include "commands.h"
  43. #include "files.h"
  44. #include "lp.h"
  45. #include "lpd.h"
  46. #include "lpdfilt.h"
  47.  
  48. /*
  49.  * All filters which are supported are prototyped in lpdfilt.h
  50.  */
  51.  
  52. /* local functions - public */
  53.        void output_char __ARGS((struct filter_stream *io_stream, int c));
  54.        void output_string __ARGS((struct filter_stream *io_stream, char *s));
  55.        void stream_flush __ARGS((struct filter_stream *io_stream));
  56.  
  57. /* local functions - private */
  58. static void stream_setup __ARGS((struct filter_stream *io_stream));
  59. static int  input_char __ARGS((struct filter_stream *io_stream));
  60.  
  61.  
  62.  
  63. struct LPDfilter filter_list[] = {
  64.     {"text",        text_filter},        /* generic IF filter */
  65.  
  66.     {"ps_switch",        ps_switch_filter},    /* postscript or */
  67.                             /* text auto-switch */
  68.  
  69.     {"text_ps",        text_ps_filter},    /* postscript or */
  70.                             /* text to postscript */
  71.     { NULL,            NULLVFP}
  72. };
  73.  
  74. /*
  75.  * Wait for printer to be available.
  76.  * Only called for DOS devices (LPT1-3, COM1-4).
  77.  */
  78. static int
  79. wait_for_printer( device )
  80. struct LPDdevice *device;
  81. {
  82.     union REGS regs;
  83.  
  84. #define NOT_BUSY    0x80
  85. #define ACK        0x40
  86. #define OUT_OF_PAPER    0x20
  87. #define SELECTED    0x10
  88. #define IO_ERROR    0x08
  89.  
  90.     if( *device->name == 'L' ) {        /* LPT? */
  91.  
  92.         for(;;) {
  93.             regs.h.ah = 2;    /* READ STATUS */
  94.             regs.x.dx = *(device->name + 3) - '1';    /* 0-2 */
  95.             int86( 0x17, ®s, ®s );
  96.             if( (regs.h.ah & (NOT_BUSY|SELECTED))
  97.                 == (NOT_BUSY|SELECTED) )
  98.                 break;
  99.             YIELD;
  100.         }
  101.  
  102.     } else if( *device->name == 'C' ) {    /* COM? */
  103.  
  104.         /* This needs more work...what are the status values
  105.          * returned?
  106.          */
  107.         for(;;) {
  108.             regs.h.ah = 3;    /* READ STATUS */
  109.             regs.x.dx = *(device->name + 3) - '1';    /* 0-3 */
  110.             int86( 0x14, ®s, ®s );
  111.             if( (regs.h.ah & 0x60) != 0 )
  112.                 break;
  113.             YIELD;
  114.         }
  115.     }
  116. }
  117.  
  118. /*
  119.  * Filter "stream" I/O routines.
  120.  */
  121. static void
  122. stream_setup( io_stream )
  123. struct filter_stream *io_stream;
  124. {
  125.     if( io_stream->type == IO_SOCKET ) {
  126.         sockmode( io_stream->stream.socket, SOCK_ASCII );
  127.         sockowner( io_stream->stream.socket, Curproc );
  128.     }
  129. }
  130.  
  131. void
  132. output_char( io_stream, c )
  133. struct filter_stream *io_stream;
  134. int c;
  135. {
  136.     struct mbuf *bp;
  137.  
  138.     switch( io_stream->type ) {
  139.         case IO_SOCKET:
  140.             usputc( io_stream->stream.socket, c );
  141.             break;
  142.         case IO_FILE:
  143.             wait_for_printer( io_stream->device );
  144.             putc( c, io_stream->stream.fp );
  145.             break;
  146.         case IO_LOCAL:
  147.             bp = pushdown(NULLBUF, 1);
  148.             bp->data[0] = c;
  149.             asy_send( (io_stream->stream.ifp)->dev, bp );
  150.             (io_stream->stream.ifp)->lastsent = secclock();
  151.             break;
  152.     }
  153. }
  154.  
  155. static int
  156. input_char( io_stream )
  157. struct filter_stream *io_stream;
  158. {
  159.     int c;
  160.  
  161.     switch( io_stream->type ) {
  162.         case IO_SOCKET:
  163.             c = recvchar( io_stream->stream.socket );
  164.             break;
  165.         case IO_FILE:
  166.             c = getc( io_stream->stream.fp );
  167.             break;
  168.         case IO_LOCAL:
  169.             c = get_asy((io_stream->stream.ifp)->dev);
  170.             break;
  171.     }
  172.     return c;
  173. }
  174.  
  175. void
  176. output_string( io_stream, s )
  177. struct filter_stream *io_stream;
  178. char *s;
  179. {
  180.     struct mbuf *bp;
  181.  
  182.     switch( io_stream->type ) {
  183.         case IO_SOCKET:
  184.             usputs( io_stream->stream.socket, s );
  185.             break;
  186.         case IO_FILE:
  187.             wait_for_printer( io_stream->device );
  188.             fputs( s, io_stream->stream.fp );
  189.             break;
  190.         case IO_LOCAL:
  191.             bp = pushdown(NULLBUF, strlen(s));
  192.             strcpy( bp->data, s );
  193.             asy_send( (io_stream->stream.ifp)->dev, bp );
  194.             (io_stream->stream.ifp)->lastsent = secclock();
  195.             break;
  196.     }
  197. }
  198.  
  199. void
  200. stream_flush( io_stream )
  201. struct filter_stream *io_stream;
  202. {
  203.     if( io_stream->type == IO_FILE )
  204.         fflush( io_stream->stream.fp );
  205.     else if( io_stream->type == IO_SOCKET )
  206.         usflush( io_stream->stream.socket );
  207. }
  208.  
  209.  
  210. /*
  211.  * Write accounting information to accounting file
  212.  * Adapted from PLP
  213.  */
  214. static void
  215. write_to_af( parms, pages )
  216. struct filter_parms *parms;
  217. int pages;
  218. {
  219.     time_t current_time;
  220.     FILE *fp;
  221.  
  222.     (void)time( ¤t_time );
  223.  
  224.     if( parms->af_file && access( parms->af_file, 02 ) >= 0 ) {
  225.  
  226.         if( (fp = fopen( parms->af_file, "a" )) != NULL ) {
  227.             fprintf( fp, "%s\t%s\t%s\t%7d\t%c\t%s",
  228.                 parms->login_name   ? parms->login_name   : "NULL",
  229.                 parms->host         ? parms->host         : "NULL",
  230.                 parms->printer_name ? parms->printer_name : "NULL",
  231.                 pages,
  232.                 parms->format,
  233.                 ctime( ¤t_time ) );
  234.             fclose( fp );
  235.         }
  236.     }
  237.     YIELD;
  238. }
  239.  
  240. /*
  241.  * FILTER RULES:
  242.  *   All filters which do no network I/O must give up processing after
  243.  *   short intervals of printing using YIELD.  NOS does not implement
  244.  *   pre-emptive scheduling and therefore other network activity will
  245.  *   be paused while printing.
  246.  */
  247.  
  248.  
  249. /*
  250.  * Standard text filter.
  251.  */
  252. void
  253. text_filter( unused, vparms, unused2 )
  254. int unused;
  255. void *vparms;
  256. void *unused2;
  257. {
  258.     struct filter_parms *parms;
  259.     int c, i, x;
  260.     int nchars = 0, nlines = 0, npages;
  261.     char *indent_string;
  262.  
  263.     parms = (struct filter_parms *)vparms;
  264.     npages = parms->pages;                /* count banner page */
  265.  
  266. #ifdef LPD_DEBUG
  267.     tprintf( "text_filter( %p, %p, %c )\n", parms, parms->sync, parms->format );
  268.     tprintf( "input = %d, output = %d\n", parms->input.type, parms->output.type );
  269.     tflush();
  270. #endif
  271.  
  272.     if( parms->indent ) {
  273.  
  274.         /* build indent string */
  275.         indent_string = malloc( parms->indent+1 );
  276.         for( i = 0; i < parms->indent; i++ )
  277.             indent_string[i] = ' ';
  278.         indent_string[i] = NULL;
  279.  
  280.         /* indent first line */
  281.         output_string( &parms->output, indent_string );
  282.     }
  283.  
  284.     for( ;; ) {
  285.         c = input_char( &parms->input );
  286.  
  287.         if( c == EOF ) {
  288.             break;
  289.         } else if( parms->literal ) {
  290.             output_char( &parms->output, c );
  291.             if( ++nchars > 128 ) {
  292.                 nchars = 0;
  293.                 YIELD;
  294.             }
  295.         } else if( c == '\n' || c == '\r' ) {
  296.             if( c == '\n' && (parms->output.device->flags & CRMOD ) )
  297.                 output_char( &parms->output, '\r' );
  298.             nchars = 0;
  299.             output_char( &parms->output, c );
  300.             if( ++nlines > parms->length ) {
  301.                 nlines = 0;
  302.                 npages++;
  303.             }
  304.             if( parms->indent )
  305.                 output_string( &parms->output, indent_string );
  306.             YIELD;
  307.         } else if( c == '\f' ) {
  308.             nchars = 0;
  309.             nlines = 0;
  310.             npages++;
  311.             output_char( &parms->output, c );
  312.             if( parms->indent )
  313.                 output_string( &parms->output, indent_string );
  314.             YIELD;
  315.         } else if( c == '\b' ) {
  316.             if( --nchars < 0 )
  317.                 nchars = 0;
  318.             output_char( &parms->output, c );
  319.         } else if( c == '\t' ) {
  320.             if( parms->output.device->flags & XTABS ) {
  321.                 x = 8 - ((nchars + 8) % 8);
  322.                 if( nchars + x < parms->width )
  323.                     while( x-- > 0 )
  324.                         output_char( &parms->output, ' ' );
  325.             }
  326.         } else if( ++nchars < parms->width )
  327.             output_char( &parms->output, c );
  328.     }
  329.     if( !parms->literal ) {
  330.         if( nchars > 0 ) {
  331.             output_char( &parms->output, '\r' );
  332.             output_char( &parms->output, '\n' );
  333.             nlines++;
  334.         }
  335.         if( nlines > 0 ) {
  336.             output_char( &parms->output, '\f' );
  337.             npages++;
  338.         }
  339.     }
  340.     stream_flush( &parms->output );
  341.     YIELD;
  342.  
  343.     if( parms->indent )
  344.         free( indent_string );
  345.  
  346.     write_to_af( parms, npages );
  347.  
  348.     if( parms->sync )        /* TRUE if not called from ps_text */
  349.         psignal( parms->sync, 0 );
  350. }
  351.  
  352.  
  353. /*
  354.  * encapsulated-postscript/regular text auto-switch filter.
  355.  *
  356.  * If file starts with '%!' the file must be PostScript.
  357.  * Use the ps_start, ps_end, and default_ps parameters as appropriate to
  358.  * place the printer in the correct mode.
  359.  *
  360.  * Otherwise, send the file through the default text_filter.
  361.  *
  362.  * BUGS: must be fed a file, if fed a stream, the first two characters
  363.  *       of a non-PostScript stream will be lost.
  364.  */
  365. void
  366. ps_switch_filter( unused, vparms, unused2 )
  367. int unused;
  368. void *vparms;
  369. void *unused2;
  370. {
  371.     struct filter_parms *parms;
  372.     int c;
  373.     int *sync, postscript;
  374.     char *start, *end;
  375.  
  376.     parms = (struct filter_parms *)vparms;
  377.  
  378. #ifdef LPD_DEBUG
  379.     tprintf( "ps_switch_filter( %c )\n", parms->format );
  380.     tflush();
  381. #endif
  382.  
  383.     postscript = 0;
  384.     start = end = NULL;
  385.  
  386.     if( parms->format != 'p' ) {
  387.         /*
  388.          * See if file is encapsulated-postscript
  389.          */
  390.         c = input_char( &parms->input );
  391.         if( c == '%' ) {        /* maybe */
  392.             c = input_char( &parms->input );
  393.             if( c == '!' ) {    /* YES! */
  394.                 postscript = 1;
  395.  
  396.                 if( !parms->default_ps ) {
  397.                     start = parms->ps_start;
  398.                     end = parms->ps_end;
  399.                 }
  400.             }
  401.         }
  402.         rewind( parms->input.stream.fp );
  403.     }
  404.  
  405.     YIELD;
  406.     if( !postscript ) {
  407.         if( parms->default_ps ) {
  408.             start = parms->ps_end;
  409.             end = parms->ps_start;
  410.         }
  411.     }
  412.     /*
  413.      * Place the printer in Standard Text or PostScript mode as
  414.      * appropriate.
  415.      */
  416.     if( start )
  417.         output_string( &parms->output, start );
  418.     /*
  419.      * save sync address so that text_filter will not signal our
  420.      * parent since output may not be complete.
  421.      */
  422.     sync = parms->sync;
  423.     parms->sync = 0;
  424.  
  425.     /*
  426.      * call the standard text_filter.
  427.      */
  428.     if( postscript )        /* PostScript files must be literal */
  429.         parms->literal = 1;
  430.     text_filter( unused, vparms, unused2 );
  431.     YIELD;
  432.  
  433.     /*
  434.      * Place the printer back into the default mode.
  435.      */
  436.     if( end )
  437.         output_string( &parms->output, end );
  438.     /*
  439.      * signal our parent
  440.      */
  441.     psignal( sync, 0 );
  442. }
  443.  
  444.  
  445. /*
  446.  * encapsulated-postscript/regular text to postscript filter.
  447.  *
  448.  * If file starts with '%!' the file must be PostScript.
  449.  * Send file directly to printer.
  450.  *
  451.  * Otherwise, send the text-to-postscript leader file '/etc/lpt.ps'
  452.  * followed by the text file.
  453.  *
  454.  * BUGS: must be fed a file, if fed a stream, the first two characters
  455.  *       of a non-PostScript stream will be lost.
  456.  */
  457. void
  458. text_ps_filter( unused, vparms, unused2 )
  459. int unused;
  460. void *vparms;
  461. void *unused2;
  462. {
  463.     struct filter_parms *parms;
  464.     int c;
  465.     int *sync, postscript;
  466.     FILE *leader_fp, *original_fp;
  467.     struct filter_stream original_file;
  468.  
  469.     parms = (struct filter_parms *)vparms;
  470.  
  471. #ifdef LPD_DEBUG
  472.     tprintf( "text_ps_filter( %c )\n", parms->format );
  473.     tflush();
  474. #endif
  475.  
  476.     postscript = 0;
  477.  
  478.     if( parms->format != 'p' ) {
  479.         /*
  480.          * See if file is encapsulated-postscript
  481.          */
  482.         c = input_char( &parms->input );
  483.         if( c == '%' ) {        /* maybe */
  484.             c = input_char( &parms->input );
  485.             if( c == '!' )        /* YES! */
  486.                 postscript = 1;
  487.         }
  488.         rewind( parms->input.stream.fp );
  489.     }
  490.  
  491.     YIELD;
  492.     /*
  493.      * save sync address so that text_filter will not signal our
  494.      * parent since output may not be complete.
  495.      */
  496.     sync = parms->sync;
  497.     parms->sync = 0;
  498.  
  499.     if( !postscript ) {
  500.         /*
  501.          * First, the text-to-postscript leader file must be
  502.          * sent to the printer.
  503.          */
  504.         original_file = parms->input;    /* save for later */
  505.  
  506.         if( (leader_fp = fopen( "/etc/lpt.ps", "r" )) != NULL ) {
  507.             parms->input.stream.fp = leader_fp;
  508.             parms->input.type = IO_FILE;
  509.             parms->literal = 1;
  510.             /*
  511.              * Now, send the leader through the text_filter.
  512.              */
  513.             text_filter( unused, vparms, unused2 );
  514.             YIELD;
  515.         }
  516.         parms->input = original_file;    /* restore */
  517.     }
  518.  
  519.     /*
  520.      * call the standard text_filter.  Both file types must now be literal.
  521.      */
  522.     parms->literal = 1;
  523.     text_filter( unused, vparms, unused2 );
  524.     YIELD;
  525.  
  526.     /*
  527.      * signal our parent
  528.      */
  529.     psignal( sync, 0 );
  530. }
  531.  
  532.  
  533. /*
  534.  * Format the input file as UNIX pr(1) and send output to socket which
  535.  * should be "piped" to the corresponding IF filter.
  536.  */
  537. void
  538. pr_filter( unused, vparms, unused2 )
  539. int unused;
  540. void *vparms;
  541. void *unused2;
  542. {
  543.     struct pr_parms *parms;
  544.     int line_count, i;
  545.     char buffer[512];
  546.     char page_string[5], *time_string;
  547.     int page_number, text_lines, page_length;
  548.     time_t current_time;
  549.  
  550.     parms = (struct pr_parms *)vparms;
  551.  
  552. #ifdef LPD_DEBUG
  553.     tputs( "pr_filter()\n" );
  554.     tflush();
  555. #endif
  556.  
  557.     sockmode( parms->out_s, SOCK_ASCII );
  558.     sockowner( parms->out_s, Curproc );    /* We own it now */
  559.  
  560.     page_number = 1;
  561.     text_lines = parms->length - PR_TOP_MARGIN - PR_BOTTOM_MARGIN;
  562.  
  563.     (void) time( ¤t_time );
  564.     time_string = ctime( ¤t_time );
  565.     rip( time_string );
  566.  
  567.     if( fgets( buffer, 510, parms->file_fp ) == NULL )
  568.         goto EXIT;
  569.  
  570.     for( ;; ) {
  571.         line_count = 1;
  572.  
  573.         for( i = 0;  i < PR_TOP_MARGIN/2;  i++ )
  574.             usputc( parms->out_s, '\n' );
  575.  
  576.         usputs( parms->out_s, time_string );
  577.         usputs( parms->out_s, "  " );
  578.         usputs( parms->out_s, parms->title );
  579.         usputs( parms->out_s, " Page " );
  580.         sprintf( page_string, "%d\n", page_number);
  581.         usputs( parms->out_s, page_string );
  582.  
  583.         for( i = 0;  i < PR_TOP_MARGIN/2;  i++ )
  584.             usputc( parms->out_s, '\n' );
  585.  
  586.         while( line_count <= text_lines ) {
  587.             line_count++;
  588.             if( *buffer == '\f' ) {
  589.                 usputc( parms->out_s, '\n' );
  590.             } else {
  591.                 usputs( parms->out_s, buffer );
  592.                 if( fgets( buffer, 510, parms->file_fp ) == NULL )
  593.                     goto EXIT;
  594.             }
  595.         }
  596.         if( *buffer == '\f' ) {
  597.             if( fgets( buffer, 510, parms->file_fp ) == NULL )
  598.                 goto EXIT;
  599.         }
  600.  
  601.         /* bottom margin  */
  602.         for( i = 0;  i < PR_BOTTOM_MARGIN;  i++ )
  603.             usputc( parms->out_s, '\n' );
  604.  
  605.         page_number++;
  606.     }
  607.  
  608.   EXIT:   /* finish last page */
  609.  
  610.     usputc( parms->out_s, '\f' );
  611.     close_s( parms->out_s );
  612. }
  613.